﻿using System;
using System.Collections.Generic;
using System.Data;

namespace Flagwind.Data
{
	/// <summary>
	/// 实体类命令，将实体类转换成合适的 SQL 更新语句和参数。
	/// </summary>
	public class EntityCommand
	{
		private IEntity currEntity;

		/// <summary>
		/// 当前表名称，带中括号
		/// </summary>
		private string currTableName = string.Empty;

		private IDataProvider _dataProvider;
		private List<IDataParameter> _insertParas;
		private List<IDataParameter> _updateParas;
		private List<IDataParameter> _deleteParas;

		/// <summary>
		/// 插入数据的时候是否插入自增列，默认否
		/// </summary>
		public bool IdentityEnable = false;

		public EntityCommand(IEntity entity, IDataProvider dataProvider)
		{
			this.currEntity = entity;
			this._dataProvider = dataProvider;
			this.currTableName = entity.GetSchemeTableName();
		}

		private string[] _targetFields;

		/// <summary>
		/// 要操作的目标表的所有字段名
		/// </summary>
		public string[] TargetFields
		{
			get
			{
				if(_targetFields == null || _targetFields.Length == 0)
				{
					_targetFields = this.currEntity.GetPropertyNames();
				}
				return _targetFields;
			}
			set
			{
				_targetFields = value;
			}
		}

		#region 命令属性

		private string _insertCommand;

		public string InsertCommand
		{
			get
			{
				if(_insertCommand == null)
				{
					_insertParas = new List<IDataParameter>();
					_insertCommand = "INSERT INTO " + currTableName;
					string fields = "";
					string values = "";
					List<string> currFields = new List<string>();
					if(this.IdentityEnable)
					{
						currFields.AddRange(this.TargetFields);
					}
					else
					{
						string identityName = currEntity.GetIdentity();
						foreach(string field in this.TargetFields)
						{
							if(identityName != field)
							{
								currFields.Add(field);
							}
						}
					}
					foreach(string field in currFields)
					{
						fields += ",[" + field + "]";
						string paraName = "@" + field.Replace(" ", "");
						values += "," + paraName;
						IDataParameter para = this._dataProvider.GetParameter(paraName, this.currEntity.GetPropertyValue(field));
						para.SourceColumn = field;
						_insertParas.Add(para);
					}
					_insertCommand = _insertCommand + "(" + fields.TrimStart(',') + ") VALUES (" + values.TrimStart(',') + ")";
				}
				return _insertCommand;
			}
			private set
			{
				_insertCommand = value;
			}
		}

		private string _updateCommand;

		public string UpdateCommand
		{
			get
			{
				if(_updateCommand == null)
				{
					if(this.currEntity.GetPrimaryKey().Count == 0)
					{
						throw new Exception("实体类没有指定主键，无法生成Update语句。");
					}
					_updateParas = new List<IDataParameter>();
					_updateCommand = "UPDATE " + currTableName + " SET ";
					string values = "";
					string condition = "";
					foreach(string field in this.TargetFields)
					{
						string paraName = "@" + field.Replace(" ", "");
						if(this.currEntity.GetPrimaryKey().Contains(field))
						{
							//当前字段为主键，不能被更新
							condition += " AND [" + field + "] = " + paraName;
						}
						else
						{
							values += ",[" + field + "] = " + paraName;
						}
						IDataParameter para = this._dataProvider.GetParameter(paraName, this.currEntity.GetPropertyValue(field));
						para.SourceColumn = field;
						_updateParas.Add(para);
					}
					_updateCommand = _updateCommand + values.TrimStart(',') + " WHERE " + condition.Substring(" AND ".Length);
				}
				return _updateCommand;
			}
			private set
			{
				_updateCommand = value;
			}
		}

		private string _deleteCommand;

		public string DeleteCommand
		{
			get
			{
				if(_deleteCommand == null)
				{
					if(this.currEntity.GetPrimaryKey().Count == 0)
					{
						throw new Exception("EntityCommand Error:实体类没有指定主键，无法生成Delete语句。");
					}
					_deleteParas = new List<IDataParameter>();
					_deleteCommand = "DELETE FROM " + currTableName + " WHERE ";
					string condition = "";
					foreach(string key in this.currEntity.GetPrimaryKey())
					{
						string paraName = "@P" + key.Replace(" ", "");
						condition += " AND [" + key + "]=" + paraName;
						IDataParameter para = this._dataProvider.GetParameter(paraName, this.currEntity.GetPropertyValue(key));
						para.SourceColumn = key;
						this._deleteParas.Add(para);
					}
					_deleteCommand = _deleteCommand + " " + condition.Substring(" AND ".Length);
				}
				return _deleteCommand;
			}
			private set
			{
				_deleteCommand = value;
			}
		}

		private string _createTableCommand;

		/// <summary>
		/// 获取创建表的命令脚本
		/// </summary>
		public string CreateTableCommand
		{
			get
			{
				if(_createTableCommand == null)
				{
					string script = @"
CREATE TABLE @TABLENAME(
@FIELDS
)
";
					if(this._dataProvider.ProviderType == DataProviderType.PostgreSQL && !string.IsNullOrEmpty(currEntity.GetIdentity()))
					{
						string seq = "CREATE SEQUENCE " + currEntity.GetMappingName() + "_" + currEntity.GetIdentity() + "_" + "seq INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1;";
						script = seq + script;
					}
					else if(this._dataProvider.ProviderType == DataProviderType.Oracle && !string.IsNullOrEmpty(currEntity.GetIdentity()))
					{
						// --; 语句分割符号
						string seqTemp = @"
CREATE SEQUENCE @TableName_@IDName_SEQ MINVALUE 1 NOMAXVALUE INCREMENT BY 1 START WITH 1 NOCACHE
;--
CREATE OR REPLACE TRIGGER @TableName_INS_TRG BEFORE
  INSERT ON [@TableName] FOR EACH ROW WHEN(new.[@IDName] IS NULL)
BEGIN
  SELECT @TableName_@IDName_SEQ.NEXTVAL INTO :new.[@IDName] FROM DUAL; 
END;
;--
";
						script = script + ";--\r\n" + seqTemp.Replace("@TableName", currEntity.GetMappingName()).Replace("@IDName", currEntity.GetIdentity());
					}
					var entityFields = EntityFieldsCache.Item(this.currEntity.GetType());
					string fieldsText = "";
					foreach(string field in this.currEntity.GetPropertyNames())
					{
						string columnScript = entityFields.CreateColumnScript(this._dataProvider, this.currEntity, field);
						fieldsText = fieldsText + "," + columnScript + "\r\n";
					}
					string tableName = this._dataProvider.PrepareSQL(currTableName);
					_createTableCommand = script.Replace("@TABLENAME", tableName).Replace("@FIELDS", fieldsText.Substring(1));
				}
				return _createTableCommand;
			}
		}

		#endregion

		#region 参数

		public IDataParameter[] InsertParameters
		{
			get
			{
				if(_insertParas != null)
				{
					return _insertParas.ToArray();
				}
				else
				{
					return null;
				}
			}
		}

		public IDataParameter[] UpdateParameters
		{
			get
			{
				if(_updateParas != null)
				{
					return _updateParas.ToArray();
				}
				else
				{
					return null;
				}
			}
		}

		public IDataParameter[] DeleteParameters
		{
			get
			{
				if(_deleteParas != null)
				{
					return _deleteParas.ToArray();
				}
				else
				{
					return null;
				}
			}
		}

		#endregion
	}
}